/*
* Copyright 2012 SAP AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sap.research.connectivity.gw;
import static org.springframework.roo.model.RooJavaType.ROO_JAVA_BEAN;
import static org.springframework.roo.model.RooJavaType.ROO_JPA_ACTIVE_RECORD;
import static org.springframework.roo.model.RooJavaType.ROO_TO_STRING;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.SortedSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.springframework.roo.classpath.TypeLocationService;
import org.springframework.roo.classpath.TypeManagementService;
import org.springframework.roo.classpath.converters.JavaTypeConverter;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.operations.Cardinality;
import org.springframework.roo.classpath.operations.Fetch;
import org.springframework.roo.classpath.operations.FieldCommands;
import org.springframework.roo.file.monitor.event.FileDetails;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.process.manager.MutableFile;
import org.springframework.roo.project.Dependency;
import org.springframework.roo.project.Path;
import org.springframework.roo.project.PathResolver;
import org.springframework.roo.project.ProjectOperations;
import org.springframework.roo.support.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.sap.research.connectivity.gw.parsers.JavaSourceField;
import com.sap.research.connectivity.gw.parsers.JavaSourceFieldBuilder;
import com.sap.research.connectivity.gw.parsers.JavaSourceFileEditor;
import com.sap.research.connectivity.gw.parsers.JavaSourceMethod;
import com.sap.research.connectivity.gw.parsers.JavaSourceMethodBuilder;
import com.sap.research.connectivity.gw.parsers.MetadataXMLParser;
@Component
public class GWOperationsUtils {
/**
* Get hold of a JDK Logger
*/
protected Logger log = Logger.getLogger(getClass().getName());
protected static final char SEPARATOR = GwUtils.SEPARATOR;
/**
* Get a reference to the FileManager from the underlying OSGi container. Make sure you
* are referencing the Roo bundle which contains this service in your add-on pom.xml.
*
* Using the Roo file manager instead if java.io.File gives you automatic rollback in case
* an Exception is thrown.
*/
@Reference protected FileManager fileManager;
/**
* Get a reference to the ProjectOperations from the underlying OSGi container. Make sure you
* are referencing the Roo bundle which contains this service in your add-on pom.xml.
*/
@Reference protected ProjectOperations projectOperations;
/**
* Use TypeLocationService to find types which are annotated with a given annotation in the project
*/
@Reference protected TypeLocationService typeLocationService;
@Reference protected PathResolver pathResolver;
@Reference protected TypeManagementService typeManagementService;
/* ------------------------------------------------------------------------------------------------------------------
* SAP RESEARCH OWN CODE
*
*
*/
/*
* Used for sub-package path of the connectivity classes
*/
public static final String oDataFolder = "connectivity";
public static final String domain = "domain";
public static final String web = "web";
protected static final AnnotationMetadataBuilder ROO_JAVA_BEAN_BUILDER = new AnnotationMetadataBuilder(ROO_JAVA_BEAN);
protected static final AnnotationMetadataBuilder ROO_TO_STRING_BUILDER = new AnnotationMetadataBuilder(ROO_TO_STRING);
protected static final AnnotationMetadataBuilder ROO_JPA_ACTIVE_RECORD_BUILDER = new AnnotationMetadataBuilder(ROO_JPA_ACTIVE_RECORD);
protected static final String PERSISTENCE_XML = "META-INF/persistence.xml";
private static final String ENCODED_KEY = "encodedKey";
private static final String DECODED_KEY = "decodedKey";
private static final String ODATA_KEY = "ODataKey";
public void addODataDependenciesToPom() {
List<Dependency> dependencies = new ArrayList<Dependency>();
// Install dependencies defined in external XML file
for (Element dependencyElement : XmlUtils.findElements("/configuration/batch/dependencies/dependency", XmlUtils.getConfiguration(getClass()))) {
dependencies.add(new Dependency(dependencyElement));
}
// Add all new dependencies to pom.xml
projectOperations.addDependencies("", dependencies);
}
public void addOdataConnectivityClass() {
Map<String, String> replacements = new HashMap<String, String>();
replacements.put("<<PACKAGE>>", "package " + getTopLevelPackageName() + "." + oDataFolder + ";\n");
GwUtils.createClassFileFromTemplate(getTopLevelPackageName(), getSubPackagePath(oDataFolder), "ODataConnectivity_template.java",
"ODataConnectivity.java", replacements, fileManager, getClass());
}
/*
* This method should dump all the metadata existing at the specified url.
* It calls an external standalone java app, which should be present in user home (regardless of OS)
*/
public String getMetadataString(String url, String user, String pass, String host, String port, int timeOut) throws Exception {
String returnString = "";
try {
String execArgs[] = new String[] {"java", "-jar",
System.getProperty("user.home") + SEPARATOR + "appToRetrieveOdataMetadata.jar",
url, user, pass, host, port};
final Process theProcess = Runtime.getRuntime().exec(execArgs);
Callable<String> call = new Callable<String>() {
public String call() throws Exception {
String returnString = "";
try {
BufferedReader inStream = new BufferedReader(new InputStreamReader( theProcess.getInputStream() ));
returnString = IOUtils.toString(inStream);
IOUtils.closeQuietly(inStream);
//if (theProcess.exitValue() != 0)
theProcess.waitFor();
} catch (InterruptedException e) {
throw new TimeoutException();
//log.severe("The call to the Gateway Service was interrupted.");
}
return returnString;
}
};
final ExecutorService theExecutor = Executors.newSingleThreadExecutor();
Future<String> futureResultOfCall = theExecutor.submit(call);
try
{
returnString = futureResultOfCall.get(timeOut, TimeUnit.SECONDS);
}
catch (TimeoutException ex)
{
throw new TimeoutException("The Gateway Service call timed out. Please try again or check your settings.");
}
catch (ExecutionException ex)
{
throw new RuntimeException("The Gateway Service call did not complete due to an execution error. " + ex.getCause().getLocalizedMessage());
}
finally {
theExecutor.shutdownNow();
}
} catch (InterruptedException ex) {
throw new InterruptedException("The Gateway Service call did not complete due to an unexpected interruption.");
} catch(IOException e) {
throw new IOException("Error when retrieving metadata from the Gateway Service.");
}
return returnString;
}
public String getTopLevelPackageName() {
return projectOperations.getFocusedTopLevelPackage().getFullyQualifiedPackageName();
}
public String getSubPackagePath(String subPackageName) {
String packagePath = getTopLevelPackageName().replace('.', SEPARATOR);
PathResolver pathResolver = projectOperations.getPathResolver();
String path = pathResolver.getFocusedIdentifier(Path.SRC_MAIN_JAVA, packagePath + SEPARATOR + subPackageName);
return path;
}
public JavaSourceFileEditor getJavaFileEditor(final String subPackagePathName, final String className) {
return getJavaFileEditor(subPackagePathName, className, true);
}
public JavaSourceFileEditor getJavaFileEditor(final String subPackagePathName, final String className, final boolean createIfNotExists) {
String entityClassPath = getSubPackagePath(subPackagePathName) + SEPARATOR + className + ".java";
MutableFile sourceEntityFile = null;
JavaSourceFileEditor entityClassFile = null;
if (fileManager.exists(entityClassPath)) {
sourceEntityFile = fileManager.updateFile(entityClassPath);
entityClassFile = new JavaSourceFileEditor(sourceEntityFile);
}
else if (createIfNotExists) {
sourceEntityFile = fileManager.createFile(entityClassPath);
entityClassFile = new JavaSourceFileEditor(sourceEntityFile);
}
return entityClassFile;
}
public Map<String[], String> getFieldsOfRemoteEntity(String entityClassName, String nameSpace) {
Map<String[], String> fields = new HashMap<String[], String>();
String metaDataPath = getSubPackagePath(oDataFolder);
String metaDataFile = metaDataPath + SEPARATOR + nameSpace +"_metadata.xml";
InputStream metaDataIs = fileManager.getInputStream(metaDataFile);
Document doc;
MetadataXMLParser xmlParser;
try {
doc = XmlUtils.getDocumentBuilder().parse(metaDataIs);
xmlParser = new MetadataXMLParser(doc, entityClassName);
xmlParser.parse();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
fields = xmlParser.getFields();
return fields;
}
public void addRemoteFieldInPersistenceMethods(JavaSourceFileEditor entityClassFile, Map.Entry<String[], String> fieldObj) {
ArrayList<JavaSourceMethod> globalMethodList = entityClassFile.getGlobalMethodList();
String pluralRemoteEntity = GwUtils.getInflectorPlural(entityClassFile.CLASS_NAME, Locale.ENGLISH);
String smallRemoteEntity = StringUtils.uncapitalize(entityClassFile.CLASS_NAME);
for (JavaSourceMethod method : globalMethodList) {
String methodName = method.getMethodName();
/*
* We insert the new field in the persist and merge methods
*/
if (methodName.endsWith("persist") || methodName.endsWith("merge")) {
StringBuffer methodBody = new StringBuffer(method.getMethodBody());
methodBody.insert(methodBody.lastIndexOf(".execute()"), makeGWPersistFieldCode("", fieldObj));
method.setMethodBody(methodBody.toString());
}
/*
* We insert the new field in the findAll and find<Entity>Entries methods
*/
else if (methodName.endsWith("findAll" + pluralRemoteEntity) || methodName.endsWith("find" + entityClassFile.CLASS_NAME + "Entries")) {
StringBuffer methodBody = new StringBuffer(method.getMethodBody());
methodBody.insert(methodBody.indexOf("virtual" + entityClassFile.CLASS_NAME + "List.add"),
makeGWShowFieldCode("", smallRemoteEntity + "Instance", smallRemoteEntity + "Item", fieldObj));
method.setMethodBody(methodBody.toString());
}
/*
* We insert the new field in the find<Entity> method
*/
else if (methodName.endsWith("find" + entityClassFile.CLASS_NAME)) {
StringBuffer methodBody = new StringBuffer(method.getMethodBody());
methodBody.insert(methodBody.indexOf("return "),
makeGWShowFieldCode("", "virtual" + entityClassFile.CLASS_NAME, smallRemoteEntity, fieldObj));
method.setMethodBody(methodBody.toString());
}
}
}
public void addLocalFieldInPersistenceMethods(JavaSourceFileEditor entityClassFile, String fieldName, String fieldType) {
ArrayList<JavaSourceMethod> globalMethodList = entityClassFile.getGlobalMethodList();
String pluralRemoteEntity = GwUtils.getInflectorPlural(entityClassFile.CLASS_NAME, Locale.ENGLISH);
String smallRemoteEntity = StringUtils.uncapitalize(entityClassFile.CLASS_NAME);
for (JavaSourceMethod method : globalMethodList) {
String methodName = method.getMethodName();
/*
* We insert the new field in the findAll and find<Entity>Entries methods
*/
if (methodName.endsWith("findAll" + pluralRemoteEntity) || methodName.endsWith("find" + entityClassFile.CLASS_NAME + "Entries")) {
StringBuffer methodBody = new StringBuffer(method.getMethodBody());
methodBody.insert(methodBody.indexOf("virtual" + entityClassFile.CLASS_NAME + "List.add"),
makeLocalShowFieldCode("\t\t", smallRemoteEntity + "Instance", entityClassFile.CLASS_NAME, fieldName));
method.setMethodBody(methodBody.toString());
}
/* NO NEED TO INSERT IN THE FIND METHOD ANYMORE AS ONCE FOUND IN THE LOCAL DB, THE LOCAL FIELDS ARE AUTOMATICALLY POPULATED
* We insert the new field in the find<Entity> method
*
else if (methodName.endsWith("find" + entityClassFile.CLASS_NAME)) {
StringBuffer methodBody = new StringBuffer(method.getMethodBody());
methodBody.insert(methodBody.indexOf("return "),
makeLocalShowFieldCode("\t", "virtual" + entityClassFile.CLASS_NAME, entityClassFile.CLASS_NAME, fieldName));
method.setMethodBody(methodBody.toString());
}*/
}
}
public void addPersistenceMethods(Map<String[], String> fields, JavaSourceFileEditor entityClassFile, String remoteEntity, Map<String[], String> keys) {
// Persist
JavaSourceMethod persistMethod = new JavaSourceMethodBuilder()
.methodName("persist")
.methodPrefix("public")
.returnType("void")
.annotations("@Transactional")
.methodBody(getPersistMethodBody(fields, keys, remoteEntity))
.build();
entityClassFile.addMethod(persistMethod);
/*
* localPersist - needed to store at least ID's on the local persistence container, as currently needed by local fields, references to other entities, etc.
* TODO: keep only the id and local fields in the persisted entity, the rest should be cleared
*/
JavaSourceMethod localPersistMethod = new JavaSourceMethodBuilder()
.methodName("localPersist")
.methodPrefix("private")
.returnType("void")
.annotations("@Transactional")
.methodBody(getLocalPersistMethodBody())
.build();
entityClassFile.addMethod(localPersistMethod);
// findAll
String pluralRemoteEntity = GwUtils.getInflectorPlural(remoteEntity, Locale.ENGLISH);
JavaSourceMethod findAllMethod = new JavaSourceMethodBuilder()
.methodName("findAll" + pluralRemoteEntity)
.methodPrefix("public static")
.returnType("List" + "<" + remoteEntity + ">")
.methodBody(getfindAllMethodBody(fields, keys, remoteEntity))
.build();
entityClassFile.addMethod(findAllMethod);
// findEntries
JavaSourceMethod findEntries = new JavaSourceMethodBuilder()
.methodName("find" + remoteEntity + "Entries")
.methodPrefix("public static")
.returnType("List" + "<" + remoteEntity + ">")
.parameters(getFindEntriesMethodParameters())
.methodBody(getfindAllMethodBody(fields, keys, remoteEntity))
.build();
entityClassFile.addMethod(findEntries);
// find
JavaSourceMethod find = new JavaSourceMethodBuilder()
.methodName("find" + remoteEntity)
.methodPrefix("public static")
.returnType(remoteEntity)
.parameters(getFindMethodParameters())
.methodBody(getFindMethodBody(fields, remoteEntity))
.build();
entityClassFile.addMethod(find);
// count
JavaSourceMethod count = new JavaSourceMethodBuilder()
.methodName("count" + pluralRemoteEntity)
.methodPrefix("public static")
.returnType("long")
.methodBody(getCountMethodBody(remoteEntity))
.build();
entityClassFile.addMethod(count);
// merge
JavaSourceMethod merge = new JavaSourceMethodBuilder()
.methodName("merge")
.methodPrefix("public")
.returnType(remoteEntity)
.annotations("@Transactional")
.methodBody(getMergeMethodBody(fields, remoteEntity, keys))
.build();
entityClassFile.addMethod(merge);
/*
* localMerge - needed by local fields, references to other entities, etc.
*/
JavaSourceMethod localMerge = new JavaSourceMethodBuilder()
.methodName("localMerge")
.methodPrefix("private")
.returnType(remoteEntity)
.annotations("@Transactional")
.methodBody(getLocalMergeMethodBody(remoteEntity))
.build();
entityClassFile.addMethod(localMerge);
// remove
JavaSourceMethod remove = new JavaSourceMethodBuilder()
.methodName("remove")
.methodPrefix("public")
.returnType("void")
.annotations("@Transactional")
.methodBody(getRemoveMethodBody(remoteEntity))
.build();
entityClassFile.addMethod(remove);
/*
* localMerge - needed by local fields, references to other entities, etc.
*/
JavaSourceMethod localRemove = new JavaSourceMethodBuilder()
.methodName("localRemove")
.methodPrefix("public")
.returnType("void")
.annotations("@Transactional")
.methodBody(getLocalRemoveMethodBody(remoteEntity))
.build();
entityClassFile.addMethod(localRemove);
JavaSourceMethod getRemoteEntity = new JavaSourceMethodBuilder()
.methodName("getRemote" + remoteEntity)
.methodPrefix("public static")
.returnType("OEntity")
.parameters(getFindMethodParameters())
.methodBody(getRemoteEntityMethodBody(remoteEntity))
.build();
entityClassFile.addMethod(getRemoteEntity);
}
private String getRemoteEntityMethodBody(String remoteEntity) {
String returnString = "\t\tOEntityKey " + ODATA_KEY + " = OEntityKey.parse( " + GwUtils.GW_CONNECTION_FIELD_NAME + ".getDecodedRemoteKey(Id));\n" +
"\t\treturn " + GwUtils.GW_CONNECTION_FIELD_NAME + ".rooODataConsumer.getEntity(\"" + remoteEntity + "\", " + ODATA_KEY + ").execute();\n";
return returnString;
}
public String getRemoveMethodBody(String remoteEntity) {
String returnString = "\t\tOEntityKey " + ODATA_KEY + " = OEntityKey.parse(" + GwUtils.GW_CONNECTION_FIELD_NAME + ".getDecodedRemoteKey(Id));\n";
returnString += "\t\t" + GwUtils.GW_CONNECTION_FIELD_NAME + ".rooODataConsumer.deleteEntity(\"" + remoteEntity + "\", ODataKey).execute();\n" +
"\t\tlocalRemove();\n";
return returnString;
}
public String getLocalRemoveMethodBody(String remoteEntity) {
String returnString = "\t\tif (this.entityManager == null) this.entityManager = entityManager();\n" +
"\t\tif (this.entityManager.contains(this)) {\n" +
"\t\t\tthis.entityManager.remove(this);\n" +
"\t\t} else {\n" +
"\t\t\t" + remoteEntity + " local" + remoteEntity + " = entityManager().find(" + remoteEntity + ".class, Id);\n" +
"\t\t\tthis.entityManager.remove(local" + remoteEntity + ");\n" +
"\t\t}\n";
return returnString;
}
public String getMergeMethodBody(Map<String[], String> fields, String remoteEntity, Map<String[], String> keys) {
String returnString = "\t\tOEntity remote" + remoteEntity + " = getRemote" + remoteEntity + "(Id);\n";
returnString += "\t\tOModifyRequest<OEntity> modifyEntityRequest = " + GwUtils.GW_CONNECTION_FIELD_NAME +
".rooODataConsumer.updateEntity(remote" + remoteEntity +");\n";
returnString += "\t\tboolean modifyRequest = modifyEntityRequest\n";
for (Map.Entry<String[], String> field: fields.entrySet()){
/*
* We do not update the key fields
*/
if (!keys.containsKey(field.getKey())) {
returnString += makeGWPersistFieldCode("\t\t\t", field);
}
}
returnString += "\t\t\t.execute();\n";
returnString += "\t\t" + remoteEntity + " localMerged = localMerge();\n";
returnString += "\n";
returnString += "\t\treturn localMerged;\n";
return returnString;
}
public String getLocalMergeMethodBody(String remoteEntity) {
String returnString = "\t\tif (this.entityManager == null) this.entityManager = entityManager();\n" +
"\t\t" + remoteEntity + " merged = this.entityManager.merge(this);\n" +
"\t\tthis.entityManager.flush();\n" +
"\t\treturn merged;\n";
return returnString;
}
public String getCountMethodBody(String remoteEntity) {
String smallRemoteEntity = StringUtils.uncapitalize(remoteEntity);
String returnString = "\t\tOQueryRequest<OEntity> " + smallRemoteEntity + "List = " + GwUtils.GW_CONNECTION_FIELD_NAME + ".rooODataConsumer.getEntities(\"" + remoteEntity + "\");\n";
returnString += "\t\tint i = 0;\n";
returnString += "\t\tfor (OEntity " + smallRemoteEntity + "Item : " + smallRemoteEntity + "List) {\n";
returnString += "\t\t\ti++;\n";
returnString += "\t\t}\n";
returnString += "\t\treturn i;\n";
return returnString;
}
public String getFindMethodBody(Map<String[], String> fields, String remoteEntity) {
String smallRemoteEntity = StringUtils.uncapitalize(remoteEntity);
String returnString = "\t\tOEntity " + smallRemoteEntity + " = getRemote" + remoteEntity + "(Id);\n";
returnString += "\t\t" + remoteEntity + " virtual" + remoteEntity + " = entityManager().find(" + remoteEntity + ".class, " +
GwUtils.GW_CONNECTION_FIELD_NAME + ".getDecodedRemoteKey(Id));\n";
returnString += "\t\tif (virtual" + remoteEntity + " == null)\n" +
"\t\t\tvirtual" + remoteEntity + " = new " + remoteEntity + "();\n";
returnString += "\t\tDateTimeFormatter DTformatter = ISODateTimeFormat.dateHourMinuteSecondFraction();\n";
returnString += "\t\tDateTimeFormatter DTOformatter = ISODateTimeFormat.dateTime();\n";
for (Map.Entry<String[], String> field: fields.entrySet()){
returnString += makeGWShowFieldCode("\t\t", "virtual" + remoteEntity, smallRemoteEntity, field);
}
//returnString += "\t\t" + "virtual" + remoteEntity + ".setId(" + DECODED_KEY + ");\n";
//returnString += "\t\t" + remoteEntity + " local" + remoteEntity + " = entityManager().find(" + remoteEntity + ".class, " + DECODED_KEY + ");\n";
returnString += "\t\ttry {\n" +
"\t\t\t\n" +
"\t\t} catch (Exception relationshipsException) {\n" +
"\t\t\trelationshipsException.printStackTrace();\n" +
"\t\t};\n";
returnString += "\t\treturn " + "virtual" + remoteEntity + ";\n";
return returnString;
}
public String getControllerShowMethodBody(String remoteEntity) {
String smallRemoteEntity = StringUtils.lowerCase(remoteEntity);
String pluralRemoteEntity = GwUtils.getInflectorPlural(remoteEntity, Locale.ENGLISH);
String returnString = "";
if (existsDateFieldInController(remoteEntity)) {
returnString += "\t\taddDateTimeFormatPatterns(uiModel);\n";
}
returnString += "\t\tuiModel.addAttribute(\"" + smallRemoteEntity + "\", " + remoteEntity + ".find" + remoteEntity + "(Id));\n";
returnString += generateURLEncodingCode("Id", "\t\t");
returnString += "\t\tuiModel.addAttribute(\"itemId\", " + ENCODED_KEY + ");\n";
returnString += "\t\treturn \"" + StringUtils.lowerCase(pluralRemoteEntity) + "/show\";\n";
return returnString;
}
public ArrayList<String> getFindMethodParameters() {
ArrayList<String> parameters = new ArrayList<String>();
parameters.add("String Id");
return parameters;
}
public ArrayList<String> getFindEntriesMethodParameters() {
ArrayList<String> parameters = new ArrayList<String>();
parameters.add("int firstResult");
parameters.add("int maxResults");
return parameters;
}
public ArrayList<String> getControllerShowMethodParameters() {
ArrayList<String> parameters = new ArrayList<String>();
parameters.add("@PathVariable(\"Id\") String Id");
parameters.add("Model uiModel");
return parameters;
}
public String getfindAllMethodBody(Map<String[], String> fields, Map<String[], String> keys, String remoteEntity) {
String smallRemoteEntity = StringUtils.uncapitalize(remoteEntity);
String returnString = "\t\tOQueryRequest<OEntity> " + smallRemoteEntity + "List = " + GwUtils.GW_CONNECTION_FIELD_NAME + ".rooODataConsumer.getEntities(\"" + remoteEntity + "\");\n";
returnString += "\t\tList<" + remoteEntity + "> virtual" + remoteEntity + "List = " + "new ArrayList<" + remoteEntity + ">();\n";
returnString += "\t\tfor (OEntity " + smallRemoteEntity + "Item : " + smallRemoteEntity + "List) {\n";
returnString += "\t\t\t" + remoteEntity + " " + smallRemoteEntity + "Instance = new " + remoteEntity + "();\n";
returnString += "\t\t\tDateTimeFormatter DTformatter = ISODateTimeFormat.dateHourMinuteSecondFraction();\n";
returnString += "\t\t\tDateTimeFormatter DTOformatter = ISODateTimeFormat.dateTime();\n";
for (Map.Entry<String[], String> field: fields.entrySet()) {
returnString += makeGWShowFieldCode("\t\t\t", smallRemoteEntity + "Instance", smallRemoteEntity + "Item", field);
}
String instance = smallRemoteEntity + "Instance";
returnString += generateEncodedKey(keys, 3, instance);
returnString += "\t\t\tString " + DECODED_KEY + " = " + GwUtils.GW_CONNECTION_FIELD_NAME + ".getDecodedRemoteKey(" + ODATA_KEY + ".toKeyString());\n";
/*
* Here we deal with the local part (e.g. fields, if any)
* (the idea is that if we browse through a remote list of entities, then we might encounter some that have not been created using
* the generated backend. So then we must first persist them (at least the id's)
*/
returnString += "\t\t\t" + remoteEntity + " local" + remoteEntity + " = entityManager().find(" + remoteEntity + ".class, " + DECODED_KEY + ");\n";
returnString += "\t\t\tif (local" + remoteEntity + " == null) {\n" +
"\t\t\t\t" + remoteEntity + " tempLocal" + remoteEntity + " = new " + remoteEntity + "();\n" +
"\t\t\t\ttempLocal" + remoteEntity + ".entityManager = entityManager();\n" +
"\t\t\t\ttempLocal" + remoteEntity + ".setId("+ DECODED_KEY +");\n" +
"\t\t\t\ttempLocal" + remoteEntity + ".localPersist();\n" +
"\t\t\t\tlocal" + remoteEntity + " = entityManager().find(" + remoteEntity + ".class, " + DECODED_KEY + ");\n" +
"\t\t\t}\n";
returnString += "\t\t\ttry {\n" +
"\t\t\t\t\n" +
"\t\t\t} catch (Exception relationshipsException) {\n" +
"\t\t\t\trelationshipsException.printStackTrace();\n" +
"\t\t\t};\n";
returnString += "\t\t\tvirtual" + remoteEntity + "List.add(" + smallRemoteEntity + "Instance);\n";
returnString += "\t\t}\n";
returnString += "\n";
returnString += "\t\treturn " + "virtual" + remoteEntity + "List;\n";
return returnString;
}
public String getPersistMethodBody(Map<String[], String> fields, Map<String[], String> keys, String remoteEntity) {
String returnString = "\t\tOEntity newEntity;\n";
returnString += "\n";
returnString += "\t\tOCreateRequest<OEntity> newEntityRequest = " + GwUtils.GW_CONNECTION_FIELD_NAME + ".rooODataConsumer.createEntity(\"" +
remoteEntity +"\");\n";
returnString += "\n";
returnString += "\t\tnewEntity = newEntityRequest\n";
for (Map.Entry<String[], String> field: fields.entrySet()){
returnString += makeGWPersistFieldCode("\t\t\t", field);
}
returnString += "\t\t\t.execute();\n";
/*
* Commented, as when writing to the local persistence db we don't need urlencoding
*/
//returnString += generateEncodedKey(keys, 2, "");
for (Map.Entry<String[], String> keyField: keys.entrySet()){
returnString += makeGWShowFieldCode("\t\t","this", "newEntity", keyField);
}
returnString += generateDBKeyFromODataKeys(keys, "\t\t", "");
returnString += "\t\tsetId(" + ODATA_KEY + ".toKeyString());\n";
returnString += "\t\tlocalPersist();\n";
return returnString;
}
public String getLocalPersistMethodBody() {
String returnString = "\t\tif (this.entityManager == null) this.entityManager = entityManager();\n" +
"\t\tthis.entityManager.persist(this);\n";
return returnString;
}
public String generateEncodedKey(Map<String[], String> keys, int numberOfTabs, String instance) {
String returnString = "\n";
String tabs = "";
String instanceMethod = "";
for(int i=0; i < numberOfTabs; i++){
tabs = tabs + "\t";
}
if(!instance.equals(""))
instanceMethod = instance + ".";
returnString += generateDBKeyFromODataKeys(keys, tabs, instanceMethod);
returnString += tabs + instanceMethod + "setId(" + GwUtils.GW_CONNECTION_FIELD_NAME + ".getEncodedRemoteKey(" + ODATA_KEY +".toKeyString()));\n";
return returnString;
}
public String generateURLEncodingCode(String variableToEncode, String tabs) {
String returnString = tabs + "String " + ENCODED_KEY + " = null;\n";
returnString += tabs + "try {\n";
returnString += tabs + "\t" + ENCODED_KEY + " = URLEncoder.encode(" + variableToEncode + ",\"UTF-8\");\n";
returnString += tabs + "} catch (UnsupportedEncodingException e) {\n";
returnString += tabs + "\te.printStackTrace();\n";
returnString += tabs + "}\n";
return returnString;
}
private String generateDBKeyFromODataKeys(Map<String[], String> keys, String tabs, String instanceMethod) {
String returnString;
String keyBuilderString = "";
String separator = "";
for(Map.Entry<String[], String> key: keys.entrySet()){
String remoteFieldName = key.getKey()[0];
String localFieldName = key.getKey()[1];
keyBuilderString += separator + "\"" + remoteFieldName + "\", ";
keyBuilderString += instanceMethod + "get" + StringUtils.capitalize(localFieldName) + "()";
separator = ",";
}
returnString = tabs + "OEntityKey " + ODATA_KEY + " = OEntityKey.create(" + keyBuilderString +");\n";
return returnString;
}
public String generateDecodedKey(int numberOfTabs, String keyNameToDecode) {
String returnString = "\n";
String tabs = "";
for(int i=0; i < numberOfTabs; i++){
tabs = tabs + "\t";
}
returnString += tabs + "String " + DECODED_KEY + " = \"\";\n";
returnString += tabs + "try{\n";
returnString += tabs + "\t" + DECODED_KEY + " = URLDecoder.decode(" + keyNameToDecode + ",\"UTF-8\");\n";
returnString += tabs + "}catch(UnsupportedEncodingException e){\n";
returnString += tabs + "}\n";
return returnString;
}
private String makeGWShowFieldCode(String tabLevels, String entityName, String remoteEntity, Map.Entry<String[], String> field) {
String startCast = "", endCast = "", returnString = "";
String remoteFieldName = field.getKey()[0];
String localFieldName = field.getKey()[1];
if (field.getValue().equals("DateTime")) {
returnString = tabLevels + "DateTime " + localFieldName.toLowerCase() + "DT = DTformatter.parseDateTime(" + remoteEntity +
".getProperty(\"" + remoteFieldName + "\").getValue().toString());\n";
returnString += tabLevels + "Date " + localFieldName.toLowerCase() + "ConvertedDate = " + localFieldName.toLowerCase() + "DT.toDate();\n";
returnString += tabLevels + entityName + ".set" + StringUtils.capitalize(localFieldName) + "(" + localFieldName.toLowerCase() + "ConvertedDate);\n";
} else if(field.getValue().equals("DateTimeOffset")) {
returnString = tabLevels + "DateTime " + localFieldName.toLowerCase() + "DT = DTOformatter.parseDateTime(" + remoteEntity +
".getProperty(\"" + remoteFieldName + "\").getValue().toString());\n";
returnString += tabLevels + "Date " + localFieldName.toLowerCase() + "ConvertedDate = " + localFieldName.toLowerCase() + "DT.toDate();\n";
returnString += tabLevels + entityName + ".set" + StringUtils.capitalize(localFieldName) + "(" + localFieldName.toLowerCase() + "ConvertedDate);\n";
} else {
String javaType = GwUtils.odataToJavaType(field.getValue());
startCast = GwUtils.generateCast(javaType);
if (!startCast.isEmpty())
endCast = ")";
returnString = tabLevels + entityName + ".set" + StringUtils.capitalize(localFieldName) + "(" + startCast + remoteEntity + ".getProperty(\""
+ remoteFieldName + "\").getValue().toString()" + endCast + ");\n";
}
return returnString;
}
private String makeLocalShowFieldCode(String tabLevels, String entityName, String remoteEntity, String fieldName) {
String returnString = entityName + ".set" + StringUtils.capitalize(fieldName) + "(local" + remoteEntity + "== null ? null : local" + remoteEntity
+ ".get" + StringUtils.capitalize(fieldName) + "());\n" + tabLevels;
return returnString;
}
public void addImports(JavaSourceFileEditor entityClassFile, String namespace){
ArrayList<String> connectivityImports = new ArrayList<String>();
connectivityImports.add(getTopLevelPackageName() + ".connectivity." + namespace);
connectivityImports.add(getTopLevelPackageName() + ".connectivity.ODataConnectivity");
connectivityImports.add("org.odata4j.core.OEntity");
connectivityImports.add("org.odata4j.core.OProperties");
connectivityImports.add("org.springframework.transaction.annotation.Transactional");
connectivityImports.add("java.util.List");
connectivityImports.add("java.util.ArrayList");
connectivityImports.add("java.util.Date");
connectivityImports.add("java.util.Calendar");
connectivityImports.add("org.odata4j.core.OQueryRequest");
connectivityImports.add("org.odata4j.core.OCreateRequest");
connectivityImports.add("org.odata4j.core.OModifyRequest");
connectivityImports.add("org.odata4j.core.OEntityKey");
connectivityImports.add("javax.persistence.Temporal");
connectivityImports.add("javax.persistence.TemporalType");
connectivityImports.add("org.springframework.format.annotation.DateTimeFormat");
connectivityImports.add("org.joda.time.DateTime");
connectivityImports.add("org.joda.time.format.DateTimeFormatter");
connectivityImports.add("org.joda.time.format.ISODateTimeFormat");
connectivityImports.add("org.odata4j.core.OEntityKey");
connectivityImports.add("javax.persistence.Column");
connectivityImports.add("javax.persistence.GenerationType");
connectivityImports.add("javax.persistence.GeneratedValue");
connectivityImports.add("java.net.URLDecoder");
connectivityImports.add("java.net.URLEncoder");
connectivityImports.add("java.io.UnsupportedEncodingException");
connectivityImports.add("javax.persistence.Id");
entityClassFile.addImports(connectivityImports);
}
public void addControllerImports(JavaSourceFileEditor entityClassFile){
ArrayList<String> connectivityImports = new ArrayList<String>();
connectivityImports.add("org.springframework.web.bind.annotation.PathVariable");
connectivityImports.add("org.springframework.ui.Model");
connectivityImports.add("java.net.URLEncoder");
connectivityImports.add("java.io.UnsupportedEncodingException");
entityClassFile.addImports(connectivityImports);
}
public void addGatewayFields(Map<String[], String> keys, Map<String[], String> fields, JavaSourceFileEditor entityClassFile) throws Exception{
// Add Keys
for (Map.Entry<String[], String> key: keys.entrySet()) {
addKeyInGWJavaFile(keys, entityClassFile, key);
}
// Add Fields
if (!fields.isEmpty()) {
for (Map.Entry<String[], String> field: fields.entrySet()) {
addRemoteFieldInGWJavaFile(entityClassFile, field);
addRemoteFieldInPersistenceMethods(entityClassFile, field);
}
}
}
public void addKeyInGWJavaFile(Map<String[], String> keys, JavaSourceFileEditor entityClassFile, Map.Entry<String[], String> key) {
//Map ODataFieldTypes to JavaTypes
String oDataType = key.getValue();
String javaType = GwUtils.odataToJavaType(oDataType);
String localFieldName = key.getKey()[1];
JavaSourceFieldBuilder fieldBuilder = new JavaSourceFieldBuilder()
.fieldPrefix("private")
.fieldType(javaType)
.fieldName(localFieldName)
.fieldValue("");
if (localFieldName.equals("Id"))
fieldBuilder = fieldBuilder.fieldAnnotations("@Id\n\t@Column(name = \"id\")");
// \t@GeneratedValue(strategy = GenerationType.AUTO)\n
if (key.getValue().equals("DateTime"))
fieldBuilder = fieldBuilder.fieldAnnotations("@Temporal(TemporalType.TIMESTAMP)\n\t@DateTimeFormat(style=\"M-\")");
JavaSourceField fieldDeclaration = fieldBuilder.build();
entityClassFile.addGlobalField(fieldDeclaration);
if (!localFieldName.equals("Id")) {
JavaSourceMethod getMethod = new JavaSourceMethodBuilder()
.methodName("get"+StringUtils.capitalize(localFieldName))
.methodPrefix("public")
.returnType(javaType)
.methodBody("\t\t" + "return" + " " + "this." + localFieldName + ";\n")
.build();
entityClassFile.addMethod(getMethod);
ArrayList<String> parameters = new ArrayList<String>();
parameters.add(javaType + " " + localFieldName);
JavaSourceMethod setMethod = new JavaSourceMethodBuilder()
.methodName("set"+StringUtils.capitalize(localFieldName))
.methodPrefix("public")
.returnType("void")
.parameters(parameters)
.methodBody("\t\t" + "this." + localFieldName + " = " + localFieldName + ";\n")
.build();
entityClassFile.addMethod(setMethod);
}
}
public void addRemoteFieldInGWJavaFile(JavaSourceFileEditor entityClassFile, Map.Entry<String[], String> field) throws Exception{
String fieldName = field.getKey()[1];
//Map ODataFieldTypes to JavaTypes
String oDataType = field.getValue();
String javaType = GwUtils.odataToJavaType(oDataType);
addFieldInGWJavaFile(entityClassFile, fieldName, javaType);
}
public void addFieldInGWJavaFile(JavaSourceFileEditor entityClassFile, String fieldName, String javaType) throws Exception {
addFieldInGWJavaFile(entityClassFile, fieldName, "", javaType, "");
}
private void addFieldInGWJavaFile(JavaSourceFileEditor entityClassFile, String fieldName, String fieldValue, String javaType, String annotations) throws Exception {
JavaSourceFieldBuilder fieldBuilder = new JavaSourceFieldBuilder()
.fieldPrefix("private")
.fieldType(javaType)
.fieldName(fieldName)
.fieldValue(fieldValue);
if (javaType.toLowerCase().contains("date") || javaType.toLowerCase().contains("calendar"))
annotations += "\n\t" + "@Temporal(TemporalType.TIMESTAMP)\n\t@DateTimeFormat(style=\"M-\")";
fieldBuilder = fieldBuilder.fieldAnnotations(annotations);
JavaSourceField fieldDeclaration = fieldBuilder.build();
if (entityClassFile.fieldExists(fieldDeclaration.getFieldName()))
throw new Exception("Field \"" + fieldDeclaration.getFieldName() + "\" already exists in java class file " + entityClassFile.CLASS_NAME);
entityClassFile.addGlobalField(fieldDeclaration);
JavaSourceMethod getMethod = new JavaSourceMethodBuilder()
.methodName("get"+StringUtils.capitalize(fieldName))
.methodPrefix("public")
.returnType(javaType)
.methodBody("\t\t" + "return" + " " + "this." + fieldName + ";\n")
.build();
entityClassFile.addMethod(getMethod);
ArrayList<String> parameters = new ArrayList<String>();
parameters.add(javaType + " " + fieldName);
JavaSourceMethod setMethod = new JavaSourceMethodBuilder()
.methodName("set"+StringUtils.capitalize(fieldName))
.methodPrefix("public")
.returnType("void")
.parameters(parameters)
.methodBody("\t\t" + "this." + fieldName + " = " + fieldName + ";\n")
.build();
entityClassFile.addMethod(setMethod);
}
private String makeGWPersistFieldCode(String tabLevels, Map.Entry<String[], String> fieldObj) {
String reversedCast = "", dateTimeOffsetCastStart = "", dateTimeOffsetCastEnd = "";
String remoteFieldName = fieldObj.getKey()[0];
String localFieldName = fieldObj.getKey()[1];
if (fieldObj.getValue().equals("DateTimeOffset")) {
reversedCast = "datetimeOffset";
dateTimeOffsetCastStart = "new DateTime(";
dateTimeOffsetCastEnd = ")";
}
else {
reversedCast = GwUtils.generateReversedCast(GwUtils.odataToJavaType(fieldObj.getValue()));
}
return tabLevels + ".properties(OProperties." + reversedCast + "(\"" + remoteFieldName + "\", " + dateTimeOffsetCastStart + "get"
+ StringUtils.capitalize(localFieldName) + "()" + dateTimeOffsetCastEnd + "))\n";
}
public Map.Entry<String[], String> getValidatedField(String localClassName, String fieldName, JavaSourceFileEditor entityClassFile) throws Exception {
Map.Entry<String[], String> fieldObj = null;
if (!entityClassFile.fieldExists(fieldName)) {
String nameSpace = GwUtils.getNamespaceFromClass(entityClassFile);
Map<String[], String> fields = getFieldsOfRemoteEntity(localClassName, nameSpace);
for(Map.Entry<String[], String> field : fields.entrySet()){
if (field.getKey()[0].equals(fieldName)) {
fieldObj = field;
break;
}
}
}
else {
throw new Exception("Field \"" + fieldName + "\" already exists in java class file " + localClassName);
}
return fieldObj;
}
private boolean existsDateFieldInController(String remoteEntity) {
SortedSet<FileDetails> files = fileManager.findMatchingAntPath(getSubPackagePath(web) + SEPARATOR + remoteEntity +"Controller_Roo_Controller*.aj");
for (FileDetails file : files) {
InputStream inputStream = fileManager.getInputStream(file.getCanonicalPath());
try {
if (IOUtils.toString(inputStream).contains(remoteEntity + "Controller.addDateTimeFormatPatterns(")) {
IOUtils.closeQuietly(inputStream);
return true;
}
} catch (IOException e) {
e.printStackTrace();
}
IOUtils.closeQuietly(inputStream);
}
return false;
}
public void addRelationships(Map<String, String[]> relationships, String remoteEntityName, JavaSourceFileEditor entityClassFile) throws Exception {
//TODO: still to add many to many relationships in persistence methods !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (relationships.isEmpty())
return;
entityClassFile.addImport("javax.persistence.CascadeType");
entityClassFile.addImport("org.odata4j.core.OLink");
entityClassFile.addImport("org.odata4j.core.OLinks");
for (Map.Entry<String, String[]> relation : relationships.entrySet()) {
int currentEntityIndex = relation.getValue()[0].equals(remoteEntityName) ? 0 : 2;
String fieldName = relation.getKey();
String fieldValue = "";
String javaType = relation.getValue()[2 - currentEntityIndex];
if (getJavaFileEditor(domain, javaType, false) != null) {
/*
* We process the types of association (many to many, many to one, one to one, one to many)
*/
String associationType = "";
String multiplicityEnd1 = relation.getValue()[currentEntityIndex].contains("1") ? "One" : "Many";
String multiplicityEnd2 = relation.getValue()[3 - currentEntityIndex].contains("1") ? "One" : "Many";
associationType = multiplicityEnd1 + "To" + multiplicityEnd2;
addRelationshipInPersistenceMethods(entityClassFile, fieldName, javaType, associationType);
if (multiplicityEnd2.equals("Many")) {
entityClassFile.addImport("java.util.HashSet");
entityClassFile.addImport("java.util.Set");
javaType = "Set<"+javaType+">";
fieldValue = "new Hash"+javaType+"()";
}
entityClassFile.addImport("javax.persistence." + associationType);
addFieldInGWJavaFile(entityClassFile, fieldName, fieldValue, javaType, "@" + associationType);
}
}
}
private void addRelationshipInPersistenceMethods(JavaSourceFileEditor entityClassFile, String nav, String javaType, String associationType) {
// TODO Auto-generated method stub
ArrayList<JavaSourceMethod> globalMethodList = entityClassFile.getGlobalMethodList();
String pluralRemoteEntity = GwUtils.getInflectorPlural(entityClassFile.CLASS_NAME, Locale.ENGLISH);
String smallRemoteEntity = StringUtils.uncapitalize(entityClassFile.CLASS_NAME);
for (JavaSourceMethod method : globalMethodList) {
String methodName = method.getMethodName();
/*
* We insert the relation in the persist and merge methods
*/
if (methodName.endsWith("persist")) {
StringBuffer methodBody = new StringBuffer(method.getMethodBody());
methodBody.insert(methodBody.lastIndexOf("newEntity = newEntityRequest"),
makeGWPersistRelationshipCode(nav, javaType, associationType, "\t\t"));
method.setMethodBody(methodBody.toString());
}
else if (methodName.endsWith("merge")) {
StringBuffer methodBody = new StringBuffer(method.getMethodBody());
methodBody.insert(methodBody.lastIndexOf("boolean modifyRequest = modifyEntityRequest"),
makeGWMergeRelationshipCode(nav, javaType, associationType, "\t\t"));
method.setMethodBody(methodBody.toString());
}
/*
* We insert the relation in the findAll and find<Entity>Entries methods
*/
else if (methodName.endsWith("findAll" + pluralRemoteEntity) || methodName.endsWith("find" + entityClassFile.CLASS_NAME + "Entries")) {
StringBuffer methodBody = new StringBuffer(method.getMethodBody());
int insertPosition = methodBody.indexOf("} catch (Exception relationshipsException)");
boolean isFirstManyToMany = true;
if ("OneToMany ManyToMany".contains(associationType)) {
String manyToManyInsertReferenceString = StringUtils.uncapitalize(entityClassFile.CLASS_NAME) + "Link.isCollection()) {";
if (methodBody.indexOf(manyToManyInsertReferenceString) > -1) {
insertPosition = methodBody.indexOf(manyToManyInsertReferenceString);
isFirstManyToMany = false;
}
}
methodBody.insert(insertPosition,
makeGWShowRelationshipCode(entityClassFile.CLASS_NAME, smallRemoteEntity + "Instance", smallRemoteEntity + "Item", ODATA_KEY,
nav, javaType, associationType, "\t\t", isFirstManyToMany));
method.setMethodBody(methodBody.toString());
}
/*
* We insert the relation in the find<Entity> method
*/
else if (methodName.endsWith("find" + entityClassFile.CLASS_NAME)) {
StringBuffer methodBody = new StringBuffer(method.getMethodBody());
int insertPosition = methodBody.indexOf("} catch (Exception relationshipsException)");
boolean isFirstManyToMany = true;
if ("OneToMany ManyToMany".contains(associationType)) {
String manyToManyInsertReferenceString = StringUtils.uncapitalize(entityClassFile.CLASS_NAME) + "Link.isCollection()) {";
if (methodBody.indexOf(manyToManyInsertReferenceString) > -1) {
insertPosition = methodBody.indexOf(manyToManyInsertReferenceString);
isFirstManyToMany = false;
}
}
methodBody.insert(insertPosition,
makeGWShowRelationshipCode(entityClassFile.CLASS_NAME, "virtual" + entityClassFile.CLASS_NAME, smallRemoteEntity,
"OEntityKey.parse(" + GwUtils.GW_CONNECTION_FIELD_NAME + ".getDecodedRemoteKey(Id))",
nav, javaType, associationType, "\t\t\t", isFirstManyToMany));
method.setMethodBody(methodBody.toString());
}
}
}
private String makeGWMergeRelationshipCode(String nav, String javaType, String associationType, String tabs) {
String returnString = "";
if ("ManyToOne OneToOne".contains(associationType)) {
returnString += "OEntity linked" + javaType + " = " + GwUtils.GW_CONNECTION_FIELD_NAME + ".rooODataConsumer.getEntity(\"" +
javaType + "\", " + javaType + ".getRemote" + javaType + "(" + nav + ".getId())).execute();\n";
returnString += tabs + "modifyEntityRequest = modifyEntityRequest.link(\"" + nav + "\", linked" + javaType + ");\n" + tabs;
}
return returnString;
}
private String makeGWPersistRelationshipCode(String nav, String javaType, String associationType, String tabs) {
String returnString = "";
if ("ManyToOne OneToOne".contains(associationType)) {
returnString += "OEntity linked" + javaType + " = " + GwUtils.GW_CONNECTION_FIELD_NAME + ".rooODataConsumer.getEntity(\"" +
javaType + "\", " + javaType + ".getRemote" + javaType + "(" + nav + ".getId())).execute();\n";
returnString += tabs + "newEntityRequest = newEntityRequest.link(\"" + nav + "\", linked" + javaType + ");\n" + tabs;
}
return returnString;
}
private String makeGWShowRelationshipCode(String className, String virtualLocalEntityInstance, String remoteEntity, String remoteId, String nav, String javaType,
String associationType, String tabs, boolean isFirstManyToMany) {
String smallClassName = StringUtils.uncapitalize(className);
String capitalNav = StringUtils.capitalize(nav);
String returnString = "";
if ("ManyToOne OneToOne".contains(associationType)) {
returnString += "OEntity remote" + javaType + " = " + GwUtils.GW_CONNECTION_FIELD_NAME + ".rooODataConsumer.getEntity(\"" +
className + "\", " + remoteId + ").nav(\"" + nav +
"\").execute();\n";
returnString += tabs + javaType + " virtual" + javaType + " = " + javaType + ".find" + javaType + "(remote" + javaType +
".getEntityKey().toKeyString());\n" ;
returnString += tabs + virtualLocalEntityInstance + ".set" + javaType + "(virtual" + javaType + ");\n" + tabs;
} else {
String extraReturn = "";
if (isFirstManyToMany) {
returnString += "List<OLink> " + smallClassName + "Links = " + remoteEntity + ".getLinks();\n" +
tabs + "\tfor(OLink " + smallClassName + "Link : " + smallClassName + "Links) {\n" +
tabs + "\t\tif (" + smallClassName + "Link.isCollection()) {\n";
extraReturn = "\n";
}
returnString += extraReturn + tabs + "\t\t\tif (" + smallClassName + "Link.getTitle().equals(\"" + nav + "\")) {\n" +
tabs + "\t\t\t\tSet<" + javaType + "> virtual" + javaType + "List = new HashSet<" + javaType + ">();\n" +
tabs + "\t\t\t\tList<OEntity> remote" + javaType + "List = " + GwUtils.GW_CONNECTION_FIELD_NAME + ".rooODataConsumer.getEntities(" +
"OLinks.relatedEntities(" + smallClassName + "Link.getRelation(), " + smallClassName + "Link.getTitle(), " +
smallClassName + "Link.getHref()))\n" +
tabs + "\t\t\t\t.execute().toList();\n" +
tabs + "\t\t\t\tfor (OEntity remote" + javaType + " : remote" + javaType + "List) {\n" +
tabs + "\t\t\t\t\t" + javaType + " virtual" + javaType + " = " + javaType + ".find" + javaType + "(remote" + javaType +
".getEntityKey().toKeyString());\n" +
tabs + "\t\t\t\t\tvirtual" + javaType + "List.add(virtual" + javaType + ");\n" +
tabs + "\t\t\t\t}\n" +
tabs + "\t\t\t\t" + virtualLocalEntityInstance + ".set" + capitalNav + "(virtual" + javaType + "List);\n" +
tabs + "\t\t\t}\n";
if (isFirstManyToMany)
returnString += tabs + "\t\t}\n" +
tabs + "}\n" + tabs;
}
return returnString;
}
}